package com.ideaaedi.commonspring.aop;

import com.ideaaedi.commonspring.lite.monitor.TimeWatcher;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.AnnotationAttributes;

import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * (non-javadoc)
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img
 * src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 1.0.0
 */
@Slf4j
public class TimeWatcherAdviceConfig {
    
    public static final String BEAN_NAME = "timeWatcherAdviceConfig";
 
    private final AnnotationAttributes annotationAttributes;
    
    public TimeWatcherAdviceConfig(AnnotationAttributes annotationAttributes) {
        this.annotationAttributes = Objects.requireNonNull(annotationAttributes, "annotationAttributes should not be null.");
    }
    
    @Bean(name = TimeWatcherAdvice.BEAN_NAME)
    public DefaultPointcutAdvisor timeWatcherAdvice() {
        // 参数信息
        Set<String> includePrefixes = Arrays.stream((String[])annotationAttributes.get("includePrefixes")).collect(Collectors.toSet());
        Set<String> excludePrefixes = Arrays.stream((String[])annotationAttributes.get("excludePrefixes")).collect(Collectors.toSet());
        Set<String> pointcutAnds = Arrays.stream((String[])annotationAttributes.get("pointcutAnd")).collect(Collectors.toSet());
        Set<String> pointcutOrs = Arrays.stream((String[])annotationAttributes.get("pointcutOr")).collect(Collectors.toSet());
        int aopPriority = (int)annotationAttributes.get("aopPriority");
        String pointcut = buildPointcut(pointcutAnds, pointcutOrs);
        
        log.info("registry bean '{}' with ConstructorArg includePrefixes -> {}, excludePrefixes -> {}, "
                        + "aopPriority -> {}, pointcut -> {}", TimeWatcherAdvice.BEAN_NAME, includePrefixes, excludePrefixes,
                aopPriority, pointcut);
        // 切面
        AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
        aspectJExpressionPointcut.setExpression(pointcut);
    
        // 切面逻辑
        TimeWatcherAdvice timeWatcherAdvice = new TimeWatcherAdvice(includePrefixes, excludePrefixes, aopPriority);
        
        // 增强器
        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(aspectJExpressionPointcut);
        defaultPointcutAdvisor.setAdvice(timeWatcherAdvice);
        defaultPointcutAdvisor.setOrder(timeWatcherAdvice.getOrder());
        return defaultPointcutAdvisor;
    }
    
    /**
     * 构建切点
     */
    protected String buildPointcut(Set<String> pointcutAnds, Set<String> pointcutOrs) {
        final String andConnector = " && ";
        final String orConnector = " || ";
        String and = pointcutAnds.stream().filter(StringUtils::isNotBlank)
                .collect(Collectors.joining(andConnector));
    
        String or = pointcutOrs.stream().filter(StringUtils::isNotBlank)
                .collect(Collectors.joining(orConnector));
        if (StringUtils.isBlank(and)) {
            and = "";
        } else {
            and = andConnector + and;
        }
        if (StringUtils.isBlank(or)) {
            or = "";
        } else {
            or = orConnector + or;
        }
        return String.format(TimeWatcher.POINTCUT_FORMAT, or, and);
    }
}
